#include "SpriteSystem.h"

SpriteSystem::SpriteSystem(int count)
{
	mode=1;
	ss = new spr_el[count];
	s_count=count;

	unsigned int i;
	for(i=0;i<s_count;i++)
	{
		ss[i].visible = 1;
	}

	sschanged=1;
	VBuffer = 0;
	locked=0;
	sortmode=0;
}

SpriteSystem::~SpriteSystem()
{
	delete[] ss;
}

void SpriteSystem::Draw(float x_,float y_,float z_)
{
	sys::renderedtris+=s_count*2;
	sys::renderedverts+=s_count*4;

	float cx = sys::camX-x_;
	float cy = sys::camY-y_;
	float cz = sys::camZ-z_;

	if(sortmode==1)
	{
		Sort(x_,y_,z_);
	}

	if(locked)
	{
		glDisable(GL_CULL_FACE);
		glBindBuffer(GL_ARRAY_BUFFER_ARB, VBuffer );
		glInterleavedArrays(GL_T2F_N3F_V3F,0,0);
		glDrawArrays(GL_QUADS,0,s_count*4*(locked-1));
		glEnable(GL_CULL_FACE);
	}
	else
	{
		if(sschanged)
		{
			sswidth = GetWidth();
			ssheight = GetHeight();
			ssdepht = GetDepht();
		}
		sschanged=0;

		if(true)//(sys::InFrustum(x_,y_,z_,sswidth,ssheight,ssdepht))
		{

			unsigned int i;
			glBegin(GL_QUADS);
			glColor4f(1.0f,1.0f,1.0f,1.0f);
			float x,y,z,h2,g,dx,dz,LeftX,LeftZ,RightX,RightZ;

			for(i=0;i<s_count;i++)
			{

				x=ss[i].x;
				y=ss[i].y;
				z=ss[i].z;

				h2 = ss[i].h*0.5f;

				g = (ss[i].w * 0.5f)/sqrt( (x -cx)*(x -cx) + (z-cz)*(z-cz)) ;

				dx = (z-cz)*g;
				dz= (x -cx)*g;


				LeftX = x + dx;
				LeftZ = z - dz;
							
				RightX = x -dx;
				RightZ = z +dz;

				glTexCoord2f(0,0);
				glVertex3f(LeftX,y+h2,LeftZ);

				glTexCoord2f(0,1);
				glVertex3f(LeftX,y-h2,LeftZ);

				glTexCoord2f(1,1);
				glVertex3f(RightX,y-h2,RightZ);

				glTexCoord2f(1,0);
				glVertex3f(RightX,y+h2,RightZ);
			}
			glEnd();
		}
	}
}

void SpriteSystem::SpritePos(unsigned int index,float x,float y,float z)
{
	ss[index].x = x;
	ss[index].y = y;
	ss[index].z = z;
	sschanged=1;
}

void SpriteSystem::SpriteSize(unsigned int index,float width,float height)
{
	ss[index].w = width;
	ss[index].h = height;
	sschanged=1;
}

void SpriteSystem::SpriteVisible(unsigned int index,int value)
{
	ss[index].visible  =value;
}

void SpriteSystem::SetMode(int value)
{
	mode = value;
}

float SpriteSystem::GetWidth()
{
	float minx,maxx;
	unsigned int i;

	minx = ss[0].x-ss[0].w;
	maxx = ss[0].x+ss[0].w;
	for(i=1;i<s_count;i++)
	{
		minx=min_(minx,ss[i].x-ss[i].w);
		maxx=max_(maxx,ss[i].x+ss[i].w);
	}
	return maxx-minx;
}

float SpriteSystem::GetHeight()
{
	float miny,maxy;
	unsigned int i;

	miny = ss[0].y-ss[0].h;
	maxy = ss[0].y+ss[0].h;
	for(i=1;i<s_count;i++)
	{
		miny=min_(miny,ss[i].y-ss[i].h);
		maxy=max_(maxy,ss[i].y+ss[i].h);
	}
	return maxy-miny;
}

float SpriteSystem::GetDepht()
{
	float minz,maxz;
	unsigned int i;

	minz = ss[0].z-ss[0].w;
	maxz = ss[0].z+ss[0].w;
	for(i=1;i<s_count;i++)
	{
		minz=min_(minz,ss[i].z-ss[i].w);
		maxz=max_(maxz,ss[i].z+ss[i].w);
	}
	return maxz-minz;
}

void SpriteSystem::Sort(float x_,float y_,float z_)
{
	//debug::add("sortnah");
	float cx = sys::camX-x_;
	float cy = sys::camY-y_;
	float cz = sys::camZ-z_;

	for(unsigned int j=0;j<s_count-1;j++)
	{
		for(unsigned int i=j+1;i<s_count;i++)
		{
			if(((ss[j].x -cx)*(ss[j].x -cx) + (ss[j].z-cz)*(ss[j].z-cz))<((ss[i].x -cx)*(ss[i].x -cx) + (ss[i].z-cz)*(ss[i].z-cz)))
			{
				spr_el d = ss[i];
				ss[i]=ss[j];
				ss[j] = d;
			}
		}
	}
}

void SpriteSystem::Sort(int beg,int end,float x_,float y_,float z_)
{
	float cx = sys::camX-x_;
	float cy = sys::camY-y_;
	float cz = sys::camZ-z_;
	
	for(int j=beg;j<end-1;j++)
	{
		for(int i=j+1;i<end;i++)
		{
			if(((ss[j].x -cx)*(ss[j].x -cx) + (ss[j].z-cz)*(ss[j].z-cz))<((ss[i].x -cx)*(ss[i].x -cx) + (ss[i].z-cz)*(ss[i].z-cz)))
			{
				spr_el d = ss[i];
				ss[i]=ss[j];
				ss[j] = d;
			}
		}
	}
}

void SpriteSystem::Lock(unsigned int mode)
{
	class vx
	{
	public:
		float u,v;
		float nx,ny,nz;
		float x,y,z;
	};

	if(!locked)
	{
		if(VBuffer)
		{
			glDeleteBuffers(1,&VBuffer);
			VBuffer=0;
		}

		glGenBuffers(1,&VBuffer);		
		glBindBuffer(GL_ARRAY_BUFFER_ARB,VBuffer);
		unsigned int cntquads = max_(mode,1);
		vx *pData = new vx[s_count*4*cntquads];
		unsigned int ind = 0;
		float d=180.0f / cntquads;

		for(unsigned int i=0;i<s_count;++i)
		{
			float h2 = ss[i].h*0.5f;
			

			float w2 = ss[i].w * 0.5f;

			float a=rnd(0,360);

			ind=i*4*cntquads;
			for(unsigned j=0;j<cntquads;++j)
			{
				float dx=0,dz=0;

				dx=-(float)sin(a*Api)*w2;
				dz=(float)cos(a*Api)*w2;
				unsigned int cind=ind+j*4;
				pData[cind+0].u=0;
				pData[cind+0].v=0;

				pData[cind+0].nx = ss[i].w;
				pData[cind+0].ny = ss[i].h;
				pData[cind+0].nz = ss[i].w;

				pData[cind+0].x = ss[i].x-dx;
				pData[cind+0].y = ss[i].y+h2;
				pData[cind+0].z = ss[i].z-dz;


				pData[cind+1].u=0;
				pData[cind+1].v=1;

				pData[cind+1].nx = ss[i].w;
				pData[cind+1].ny = ss[i].h;
				pData[cind+1].nz = ss[i].w;

				pData[cind+1].x = ss[i].x-dx;
				pData[cind+1].y = ss[i].y-h2;
				pData[cind+1].z = ss[i].z-dz;


				pData[cind+2].u=1;
				pData[cind+2].v=1;

				pData[cind+2].nx = ss[i].w;
				pData[cind+2].ny = ss[i].h;
				pData[cind+2].nz = ss[i].w;

				pData[cind+2].x = ss[i].x+dx;
				pData[cind+2].y = ss[i].y-h2;
				pData[cind+2].z = ss[i].z+dz;


				pData[cind+3].u=1;
				pData[cind+3].v=0;

				pData[cind+3].nx = ss[i].w;
				pData[cind+3].ny = ss[i].h;
				pData[cind+3].nz = ss[i].w;

				pData[cind+3].x = ss[i].x+dx;
				pData[cind+3].y = ss[i].y+h2;
				pData[cind+3].z = ss[i].z+dz;

				a+=d;
			}
		}


		glBufferData( GL_ARRAY_BUFFER_ARB,sizeof(vx)*s_count*4*cntquads,pData, GL_STATIC_DRAW_ARB );
		delete[] pData;
		locked=mode+1;
	}
}
void SpriteSystem::UnLock()
{
	if(locked)
	{

		locked=0;
	}
}

void SpriteSystem::SortMode(int smode)
{
	sortmode=smode;
}